package edu.caece.automaton;

import java.util.Iterator;
import java.util.Set;
import java.util.Stack;

public class PushDownAutomatonImpl extends AbstractAutomaton{
	Stack<Character> stack;
	
	public PushDownAutomatonImpl(){
		stack = new Stack<Character>();
		//Pongo el tope de la pila
		stack.add('%');
	}
	
	@Override
	public boolean run(String word) {
		int index = 0;
		this.currentState = this.startState;
		Iterator<Transition> transitionIterator;
		PushDownTransition testTransition;
		boolean stateChanged;

		stateChanged = false;
		while ((index < word.length() && !this.currentState.equals(this.trashState)) ||
				(index >= word.length() && stateChanged && index < 1000)){
			stateChanged = false;
			//para ejecucion de sartas nulas
			Character currentChar ;
			if (index < word.length())
				currentChar = word.charAt(index);
			else
				currentChar = '$'; //el $ es lambda
			if (transitions.containsKey(currentState)){
				transitionIterator = transitions.get(currentState).iterator();
				while (transitionIterator.hasNext() && !stateChanged){
					testTransition = (PushDownTransition) transitionIterator.next();
					if (testTransition.getSourceState().equals(this.currentState)){
						if ((testTransition.matches(currentChar)||
								testTransition.matches('$')) && 
								(testTransition.getStackPullSymbol() == '$' ||
								testTransition.getStackPullSymbol() == this.stack.peek())){
							if (testTransition.matches('$')) //si activo la transición lambda no avanzo en la sarta
								index--;
							if (testTransition.getStackPullSymbol() != '$')
								this.stack.pop();
							if (testTransition.getStackPushSymbol() != '$')
								this.stack.push(testTransition.getStackPushSymbol());	
							this.currentState = testTransition.getDestinationState();
							stateChanged = true;
						}
					}
				}
			}
			if (!stateChanged && index < word.length())
				this.currentState = this.trashState;
			index++;
		}

		return this.acceptStates.contains(this.currentState);
	}

	@Override
	public void reset() {
		this.currentState = this.startState;
		
	}

	@Override
	public boolean step(Character token) {
		Iterator<Transition> transitionIterator;
		PushDownTransition testTransition;
		boolean stateChanged;

		stateChanged = false;
/*
		if (index < word.length())
				currentChar = word.charAt(index);
			else
				currentChar = '$'; //el $ es lambda
*/
		if (!this.currentState.equals(this.trashState)){
			if (this.transitions.containsKey(this.currentState)){
				transitionIterator = this.transitions.get(this.currentState).iterator();
				while (transitionIterator.hasNext() && !stateChanged){
					testTransition = (PushDownTransition) transitionIterator.next();
					if (testTransition.getSourceState().equals(this.currentState)){
						if ((testTransition.matches(token)||
								testTransition.matches('$')) && 
								(testTransition.getStackPullSymbol() == '$' ||
								testTransition.getStackPullSymbol() == this.stack.peek())){
							if (testTransition.getStackPullSymbol() != '$')
								this.stack.pop();
							if (testTransition.getStackPushSymbol() != '$')
								this.stack.push(testTransition.getStackPushSymbol());	
							this.currentState = testTransition.getDestinationState();
							stateChanged = true;
						}
					}
				}
			}
			if (!stateChanged)
				this.currentState = this.trashState;
		}

		return this.acceptStates.contains(this.currentState);

	}

	@Override
	public State peek(Character token) {
		// TODO Auto-generated method stub
		return null;
	}

	public Set<State> getAcceptStates() {
		// TODO Auto-generated method stub
		return null;
	}

}
